package com.iot.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.iot.commons.ResponseResult;
import com.iot.constant.CacheKeyConstant;
import com.iot.enums.CancelContentEnum;
import com.iot.enums.LanguageEnum;
import com.iot.enums.StatusEnum;
import com.iot.mapper.FollowMapper;
import com.iot.mapper.MessageMapper;
import com.iot.model.BaseModel;
import com.iot.model.SMSPhoneModel;
import com.iot.model.dto.LocationCacheDto;
import com.iot.model.dto.SmsVerifyCodeDto;
import com.iot.model.entity.*;
import com.iot.model.query.FollowQuery;
import com.iot.model.dto.FollowDto;
import com.iot.model.vo.*;
import com.iot.service.*;
import com.iot.utils.AppPushUtils;
import com.iot.utils.DateUtil;
import com.iot.utils.SMSUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.iot.utils.ResponseResultUtil;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * FollowServiceImpl
 *
 * @author: dh
 * @date: 2024-04-22 17:25:47
 */
@Service
@RequiredArgsConstructor
public class FollowServiceImpl implements FollowService {

    private final FollowMapper followMapper;

    private final DeviceService deviceService;

    private final MessageMapper messageMapper;

    private final UserInfoService userInfoService;

    private final DeviceDataBpService deviceDataBpService;

    private final ElectronicFenceService electronicFenceService;

    private final DeviceDataStepsService deviceDataStepsService;

    private final DeviceDataLocationService deviceDataLocationService;

    private final RedisTemplate<String, Object> redisTemplate;

    private static final String DEVICE_TEMPLATE_CODE = "SMS_468435397";

    @Override
    public ResponseResult getList(FollowQuery follow) {
        if (null == follow || null == follow.getType()) {
            return ResponseResultUtil.paramFailure();
        }
        AuthInfoVo authInfoEntity = (AuthInfoVo) StpUtil.getSession().get("loginInfo");
        if (null == authInfoEntity) {
            return ResponseResultUtil.authInfoFailure();
        }
        List<FollowVo> followVoList = Lists.newArrayList();

        boolean type = follow.getType().equals(0);
        Page<FollowEntity> page = new Page<>(follow.getPageIndex(), follow.getPageSize());
        LambdaQueryWrapper<FollowEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FollowEntity::getState, StatusEnum.VALID.getKey());
        queryWrapper.eq(type, FollowEntity::getFollowAuthId, authInfoEntity.getId());
        queryWrapper.eq(!type, FollowEntity::getAuthId, authInfoEntity.getId());
        queryWrapper.orderByDesc(FollowEntity::getCreateTime);
        IPage<FollowEntity> followPage = followMapper.selectPage(page, queryWrapper);
        if (null == followPage || followPage.getTotal() == 0) {
            return ResponseResultUtil.success(0, followVoList);
        }

        List<FollowEntity> records = followPage.getRecords();
        List<Long> authIds = records.stream().map(type ? FollowEntity::getAuthId : FollowEntity::getFollowAuthId).collect(Collectors.toList());
        List<Long> electronicFenceIds = records.stream().map(FollowEntity::getElectronicFenceId).collect(Collectors.toList());

        List<UserInfoEntity> userInfoList = userInfoService.getByAuthIds(authIds);
        Map<Long, UserInfoEntity> groupByAuthId = userInfoList.stream().collect(Collectors.toMap(UserInfoEntity::getAuthId, x -> x, (obj1, obj2) -> obj2));

        Map<Long, ElectronicFenceEntity> groupByElectronicFenceId = Maps.newHashMap();
        List<ElectronicFenceEntity> electronicFenceEntities = electronicFenceService.getByIds(electronicFenceIds);
        if (CollectionUtils.isNotEmpty(electronicFenceEntities)) {
            groupByElectronicFenceId = electronicFenceEntities.stream().collect(Collectors.toMap(ElectronicFenceEntity::getId, x -> x, (obj1, obj2) -> obj2));

        }
        for (FollowEntity followEntity : records) {
            FollowVo vo = new FollowVo();
            Long followAuthId = followEntity.getFollowAuthId();
            Long authId = followEntity.getAuthId();
            vo.setId(followEntity.getId());
            UserInfoEntity userInfoEntity = groupByAuthId.get(type ? authId : followAuthId);
            if (null != userInfoEntity) {
                vo.setNickName(userInfoEntity.getNickName());
                String phone = userInfoEntity.getPhone();
                if (StringUtils.isNotEmpty(phone)) {
                    vo.setPhone(phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
                }
                vo.setAvatarsUrl(userInfoEntity.getAvatarsUrl());
            }
            vo.setDataTypes(followEntity.getDataTypes());
            Long electronicFenceId = followEntity.getElectronicFenceId();

            FollowElectronicFenceVo followElectronicFenceVo = new FollowElectronicFenceVo();
            if (null != electronicFenceId) {

                ElectronicFenceEntity entity = groupByElectronicFenceId.get(electronicFenceId);
                if (null != entity) {
                    followElectronicFenceVo.setElectronicFenceName(entity.getName());
                }
                followElectronicFenceVo.setElectronicFenceId(followEntity.getElectronicFenceId());
            }
            vo.setElectronicFence(followElectronicFenceVo);
            vo.setElectronicFenceType(followEntity.getElectronicFenceType());
            followVoList.add(vo);
        }

        return ResponseResultUtil.success(followPage.getTotal(), followVoList);
    }

    @Override
    public ResponseResult edit(FollowDto follow) {
        if (null == follow || null == follow.getId()) {
            return ResponseResultUtil.paramFailure();
        }
        FollowEntity entity = new FollowEntity();
        entity.setId(follow.getId());
        entity.setDataTypes(follow.getDataTypes());
        entity.setUpdateTime(DateUtil.now());
        followMapper.updateById(entity);
        return ResponseResultUtil.success();
    }

    @Override
    public ResponseResult bindElectronicFence(FollowDto follow) {
        if (null == follow || null == follow.getId()) {
            return ResponseResultUtil.paramFailure();
        }
        FollowEntity entity = new FollowEntity();
        entity.setId(follow.getId());
        entity.setElectronicFenceType(follow.getElectronicFenceType());
        entity.setElectronicFenceId(follow.getElectronicFenceId());
        entity.setUpdateTime(DateUtil.now());
        followMapper.updateById(entity);
        return ResponseResultUtil.success();
    }

    @Override
    public ResponseResult unBindElectronicFence(FollowDto follow) {
        if (null == follow || null == follow.getId()) {
            return ResponseResultUtil.paramFailure();
        }
        LambdaUpdateWrapper<FollowEntity> lambdaUpdate = Wrappers.lambdaUpdate();
        lambdaUpdate.eq(FollowEntity::getId, follow.getId());
        lambdaUpdate.set(FollowEntity::getElectronicFenceId, null);

        FollowEntity entity = new FollowEntity();
        entity.setUpdateTime(DateUtil.now());
        followMapper.update(entity, lambdaUpdate);
        return ResponseResultUtil.success();
    }

    @Override
    public ResponseResult cancel(FollowDto follow) {
        AuthInfoVo authInfoEntity = (AuthInfoVo) StpUtil.getSession().get("loginInfo");
        if (null == authInfoEntity) {
            return ResponseResultUtil.authInfoFailure();
        }
        if (null == follow || null == follow.getId()) {
            return ResponseResultUtil.paramFailure();
        }
        Long id = follow.getId();
        FollowEntity followEntity = followMapper.selectById(id);
        if (null == followEntity) {
            return ResponseResultUtil.failure();
        }
        FollowEntity entity = new FollowEntity();
        entity.setId(id);
        entity.setState(StatusEnum.DELETE.getKey());
        entity.setUpdateTime(DateUtil.now());
        followMapper.updateById(entity);

        UserInfoVo userInfoVo = userInfoService.getByAuthId(authInfoEntity.getId());
        if (null == userInfoVo) {
            return ResponseResultUtil.failure("用户不存在", 11006);
        }


        Long authId = followEntity.getFollowAuthId().equals(authInfoEntity.getId()) ? followEntity.getAuthId() : followEntity.getFollowAuthId();
        UserInfoVo messageVo = userInfoService.getByAuthId(authId);
        if (null == messageVo) {
            return ResponseResultUtil.failure("用户不存在", 11006);
        }

        String nickName = StringUtils.isEmpty(userInfoVo.getNickName()) ? userInfoVo.getPhone() : userInfoVo.getNickName();
        String content = CancelContentEnum.getByCode(follow.getLanguage()).replace(LanguageEnum.NICKNAME.getValue(), nickName);
        sendMessage("取消关注", content, 2, authId, userInfoVo.getUid(), messageVo.getCid(), null);
        return ResponseResultUtil.success();
    }

    private void sendMessage(String title, String content, Integer type, Long authId, Long uid, String cid, Long sid) {
        AppPushUtils.sendMessage(cid, "V Band", content);
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setTitle(title);
        messageEntity.setContent(content);
        messageEntity.setType(type);
        messageEntity.setAuthId(authId);
        messageEntity.setUid(uid);
        messageEntity.setIsRead(1);
        messageEntity.setSid(sid);
        messageEntity.setState(StatusEnum.VALID.getKey());
        messageEntity.setCreateTime(DateUtil.nowSecond());
        messageMapper.insert(messageEntity);
    }

    @Override
    public Long add(FollowDto follow) {
        FollowEntity entity = new FollowEntity();
        entity.setId(follow.getId());
        entity.setAuthId(follow.getAuthId());
        entity.setFollowAuthId(follow.getFollowAuthId());
        entity.setDataTypes(follow.getDataTypes());
        entity.setState(follow.getState());
        entity.setCreateTime(follow.getCreateTime());
        entity.setUpdateTime(follow.getUpdateTime());
        followMapper.insert(entity);
        return entity.getId();
    }

    @Override
    public ResponseResult getById(FollowQuery follow) {
        FollowEntity followEntity = followMapper.selectById(follow.getId());
        FollowVo vo = new FollowVo();
        vo.setId(followEntity.getId());
        return ResponseResultUtil.success(vo);
    }

    private boolean checkDataType(FollowEntity followEntity, String dataType) {
        String dataTypes = followEntity.getDataTypes();
        if (StringUtils.isEmpty(dataTypes) || StringUtils.isEmpty(dataType)) {
            return true;
        }
        return !dataTypes.contains(dataType);
    }

    @Override
    public ResponseResult getStepData(FollowQuery follow) {
        if (null == follow) {
            return ResponseResultUtil.paramFailure();
        }
        Long id = follow.getId();
        if (null == id || null == follow.getStartTime()) {
            return ResponseResultUtil.paramFailure();
        }
        FollowEntity followEntity = followMapper.selectById(id);
        if (null == followEntity) {
            return ResponseResultUtil.success();
        }
        if (checkDataType(followEntity, "1")) {
            return ResponseResultUtil.failure("无数据权限", 11012);
        }
        Long authId = followEntity.getFollowAuthId();
        IPage<DeviceDataStepsEntity> page = deviceDataStepsService.getByDate(follow, authId);
        if (null == page || page.getTotal() == 0) {
            return ResponseResultUtil.success(0, Lists.newArrayList());
        }
        List<DeviceDataStepsVo> voList = Lists.newArrayList();
        List<DeviceDataStepsEntity> records = page.getRecords();
        for (DeviceDataStepsEntity record : records) {
            DeviceDataStepsVo vo = new DeviceDataStepsVo();
            vo.setTime(record.getTime());
            vo.setStep(record.getStep());
            vo.setDuration(record.getDuration());
            vo.setCalorie(record.getCalorie());
            vo.setDistance(record.getDistance());
            voList.add(vo);
        }
        return ResponseResultUtil.success(page.getTotal(), voList);
    }

    @Override
    public ResponseResult getBpData(FollowQuery follow) {
        if (null == follow) {
            return ResponseResultUtil.paramFailure();
        }
        Long id = follow.getId();
        if (null == id || null == follow.getStartTime()) {
            return ResponseResultUtil.paramFailure();
        }
        FollowEntity followEntity = followMapper.selectById(id);
        if (null == followEntity) {
            return ResponseResultUtil.success();
        }
        if (checkDataType(followEntity, "4")) {
            return ResponseResultUtil.failure("无数据权限", 11012);
        }
        Long authId = followEntity.getFollowAuthId();
        IPage<DeviceDataBpEntity> page = deviceDataBpService.getByDate(follow, authId);
        if (null == page || page.getTotal() == 0) {
            return ResponseResultUtil.success(0, Lists.newArrayList());
        }
        List<DeviceDataBpVo> voList = Lists.newArrayList();
        List<DeviceDataBpEntity> records = page.getRecords();
        for (DeviceDataBpEntity record : records) {
            DeviceDataBpVo vo = new DeviceDataBpVo();
            vo.setTime(record.getTime());
            vo.setDbp(record.getDbp());
            vo.setSbp(record.getSbp());
            voList.add(vo);
        }
        return ResponseResultUtil.success(page.getTotal(), voList);
    }

    @Override
    public ResponseResult getLocationData(FollowQuery follow) {
        if (null == follow) {
            return ResponseResultUtil.paramFailure();
        }
        Long id = follow.getId();
        if (null == id || null == follow.getStartTime()) {
            return ResponseResultUtil.paramFailure();
        }
        FollowEntity followEntity = followMapper.selectById(id);
        if (null == followEntity) {
            return ResponseResultUtil.success();
        }
        if (checkDataType(followEntity, "10")) {
            return ResponseResultUtil.failure("无数据权限", 11012);
        }
        Long authId = followEntity.getFollowAuthId();
        IPage<DeviceDataLocationEntity> page = deviceDataLocationService.getByDate(follow, authId);
        if (null == page || page.getTotal() == 0) {
            return ResponseResultUtil.success(0, Lists.newArrayList());
        }
        List<DeviceDataLocationVo> voList = Lists.newArrayList();
        List<DeviceDataLocationEntity> records = page.getRecords();
        for (DeviceDataLocationEntity record : records) {
            DeviceDataLocationVo vo = new DeviceDataLocationVo();
            vo.setTime(record.getTime());
            vo.setLon(record.getLon());
            vo.setLat(record.getLat());
            voList.add(vo);
        }
        return ResponseResultUtil.success(page.getTotal(), voList);
    }

    @Override
    public Long getByAuthId(Long launchAuthId, Long authId) {
        LambdaQueryWrapper<FollowEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FollowEntity::getState, StatusEnum.VALID.getKey());
        queryWrapper.eq(FollowEntity::getAuthId, launchAuthId);
        queryWrapper.eq(FollowEntity::getFollowAuthId, authId);
        return followMapper.selectCount(queryWrapper);

    }

    @Override
    public ResponseResult send(FollowQuery follow) {
        AuthInfoVo authInfoEntity = (AuthInfoVo) StpUtil.getSession().get("loginInfo");
        if (null == authInfoEntity) {
            return ResponseResultUtil.authInfoFailure();
        }

        if (null == follow) {
            return ResponseResultUtil.paramFailure();
        }
        Long id = follow.getId();
        if (null == id) {
            return ResponseResultUtil.paramFailure();
        }
        FollowEntity followEntity = followMapper.selectById(id);
        if (null == followEntity) {
            return ResponseResultUtil.paramFailure();
        }
        DeviceEntity deviceEntity = deviceService.getByAuthId(followEntity.getAuthId());
        if (null == deviceEntity) {
            return ResponseResultUtil.paramFailure();
        }
        String phone = deviceEntity.getPhone();
        if (StringUtils.isBlank(phone)) {
            return ResponseResultUtil.failure("手表电话为空", 11016);
        }
        String imei = deviceEntity.getImei();
        if (StringUtils.isBlank(imei)) {
            return ResponseResultUtil.failure("imei为空", 11017);
        }
        UserInfoVo userInfoVo = userInfoService.getByAuthId(authInfoEntity.getId());
        if (null == userInfoVo) {
            return ResponseResultUtil.failure("用户不存在", 11006);
        }
        String cid = userInfoVo.getCid();
        if (StringUtils.isBlank(cid)) {
            return ResponseResultUtil.failure("cid为空", 11015);
        }
        SmsVerifyCodeDto dto = new SmsVerifyCodeDto();
        dto.setTemplateCode(DEVICE_TEMPLATE_CODE);
        dto.setPhoneNumber(phone);
        SMSPhoneModel aliPhoneModel = SMSUtils.sendSmsVerifyCode(dto);
        if (!aliPhoneModel.getIsSuccess()) {
            return ResponseResultUtil.failure(aliPhoneModel.getErrorMsg());
        }
        LocationCacheDto model = new LocationCacheDto();
        model.setOs(follow.getOs());
        model.setCid(cid);
        model.setId(id);
        redisTemplate.opsForValue().set(String.format(CacheKeyConstant.DEVICE_UPLOAD_KEY, imei), model, 10, TimeUnit.MINUTES);
        return ResponseResultUtil.success();
    }

}
